import { TrackOpTypes } from "vue"

// 当前正在执行的effect
export let activeEffect: ReactiveEffect | null = null

export class ReactiveEffect<T = any>{
  deps: Set<ReactiveEffect>[] = [] // 该函数在执行过程中，被加入依赖存储结构的Set集合。依赖收集时加入

  constructor(
    public fn: () => T, // ts语法，初始化fn时等于 this.fn = fn
    public scheduler?: EffectScheduler
  ) { }
  
  run() {
    try {
      activeEffect = this
      effectStack.push(this)
      cleanupEffect(this)
      return this.fn()
    } finally { 
      effectStack.pop()
      activeEffect = effectStack[effectStack.length - 1] || null
    }
  }
}

// 用于懒执行的effect
export interface ReactiveEffectRunner<T = any> {
  (): T
  effect: ReactiveEffect
}
// 自定义调度器
export type EffectScheduler = (...args: any[]) => any

/**
 * 第一层targetMap是响应式对象的map，key是target，value是propMap
 * 第二层propMap是属性的map，key是属性名，value是typeMap
 * 第三层typeMap是操作类型的map，key是操作类型（收集依赖的类型），value是effect集合（Set）
 */
export const targetMap = new WeakMap<any, Map<string | symbol, Map<TrackOpTypes, Set<ReactiveEffect>>>>()
// 这里用来模拟函数栈结构
let effectStack: ReactiveEffect[] = []

export interface ReactiveEffectOptions{
  lazy?: boolean // 是否是懒执行
  scheduler?: (job: Function) => void // 调度器
}

export function effect<T>(fn: () => T, options: ReactiveEffectOptions = {}) {
  const environment = new ReactiveEffect(fn, options.scheduler)
  if (!options || !options.lazy) {
    environment.run()
  } else {
    const runner = environment.run.bind(environment) as ReactiveEffectRunner
    runner.effect = environment
    return runner
  }
}

// 清除effect的依赖
export function cleanupEffect(effect: ReactiveEffect) {
  const { deps } = effect
  if (deps.length) {
    for (let i = 0; i < deps.length; i++) {
      deps[i].delete(effect)
    }
    deps.length = 0
  }
}